package top.canyue.word_range_service.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import top.canyue.word_range.exception.BaseException;
import top.canyue.word_range.exception.DataIsNullException;
import top.canyue.word_range.pojo.dto.WordBookDto;
import top.canyue.word_range.pojo.po.WordBook;
import top.canyue.word_range.pojo.vo.WordBookVo;
import top.canyue.word_range.result.Result;
import top.canyue.word_range.utils.PojoUtil;
import top.canyue.word_range_service.mapper.WordBookMapper;
import top.canyue.word_range_service.mapper.WordMapper;
import top.canyue.word_range_service.service.UserService;
import top.canyue.word_range_service.service.WordBookService;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class WordBookServiceImpl extends ServiceImpl<WordBookMapper, WordBook> implements WordBookService {
    final WordBookMapper wordBookMapper;
    final WordMapper wordMapper;
    @Resource
    private RedisTemplate<String, WordBookVo> redisTemplate;
    @Resource
    private ValueOperations<String, WordBookVo> valueOperations;
    final PasswordEncoder passwordEncoder;
    final UserService userService;
    // 登录超时时间(Redis数据的TTL)
    @Value("${work-range.user.login-timeout}")
    private int userLoginTimeout;
    // Redis数据前缀
    @Value("${work-range.redis.key-prefix}")
    private String redisKeyPrefix;

    @Override
    public Result<Object> addWordBook(WordBookDto wordBookDto) {
        WordBook wordBook = BeanUtil.copyProperties(wordBookDto, WordBook.class, PojoUtil.getNullPropertyNames(wordBookDto));
        wordBookMapper.insert(wordBook);
        return Result.success();
    }

    // 缓存预热
    @PostConstruct  // 容器初始化时执行
    public void preloadCache() {
        List<WordBook> wordBooks = wordBookMapper.selectList(new QueryWrapper<WordBook>());
        for (WordBook wordBook : wordBooks) {
            String cacheKey = redisKeyPrefix + "Book_" + wordBook.getId();
            WordBookVo wordBookVo = BeanUtil.copyProperties(wordBook, WordBookVo.class);
            valueOperations.set(cacheKey, wordBookVo, userLoginTimeout, TimeUnit.SECONDS);
        }
    }

    @Override
    public Result<WordBookVo> getWordBookById(String id) {
        WordBookVo wordBookVo;
        String cacheKey = redisKeyPrefix + "Book_" + id;

        // 若Redis中存在
        if (redisTemplate.hasKey(cacheKey)) {
            try {
                wordBookVo = valueOperations.get(cacheKey);
                // 校验获取的数据是否有效
                if (wordBookVo == null) {
                    throw new DataIsNullException();
                }
            } catch (Exception e) {
                // 如果反序列化失败，删除无效的缓存数据
                redisTemplate.delete(cacheKey);
                // 重新从数据库获取数据
                wordBookVo = getWordBookFromDatabase(id);
                // 重新设置缓存
                valueOperations.set(cacheKey, wordBookVo, userLoginTimeout, TimeUnit.SECONDS);
            }
        } else {
            wordBookVo = getWordBookFromDatabase(id);
            // 缓存数据，并设置合理的TTL
            valueOperations.set(cacheKey, wordBookVo, userLoginTimeout, TimeUnit.SECONDS);
        }
        return Result.success(wordBookVo);
    }

    private WordBookVo getWordBookFromDatabase(String id) {
        WordBook wordBook = wordBookMapper.selectById(id);
        if (wordBook == null) {
            throw new DataIsNullException();
        }
        WordBookVo wordBookVo = BeanUtil.copyProperties(wordBook, WordBookVo.class);
        Integer count = wordMapper.countByBookId(id);
        wordBookVo.setWordCount(count);
        return wordBookVo;
    }

    @Override
    public Result<Object> updateWordBook(WordBookDto wordBookDto) {
        WordBook wordBook = BeanUtil.copyProperties(wordBookDto, WordBook.class, PojoUtil.getNullPropertyNames(wordBookDto));
        boolean notOk = wordBookMapper.updateById(wordBook) != 1;
        if (notOk) { throw new BaseException("更新失败"); }
        return Result.success();
    }

    @Override
    public Result<List<WordBookVo>> getAllBookInfo() {
        List<WordBook> wordBooks = wordBookMapper.selectList(new QueryWrapper<WordBook>());
        List<WordBookVo> wordBookVos = BeanUtil.copyToList(wordBooks, WordBookVo.class);
        return Result.success(wordBookVos);
    }

}

